﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YunQue.Core.Common.TaskManager
{
    public abstract class LinkTaskAbstract
    {
        private LinkTaskAbstract _top;
        private LinkTaskAbstract _next;
        private int _stepIndex = 1;
        private HashSet<string> _stepTokenList;
        protected string StepName = string.Empty;
        protected string StepToken = string.Empty;
        /// <summary>
        /// 设置下一步任务，并返回下一步任务实例
        /// </summary>
        /// <param name="next"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public LinkTaskAbstract SetNext(LinkTaskAbstract next)
        {
            if (next == null) throw new ArgumentNullException(nameof(next), "下一步任务不能为空");
            if (this._top != null) this._stepTokenList = this._top._stepTokenList;
            if (this._stepTokenList == null)
            {
                this._stepTokenList = new HashSet<string>();
                this._stepTokenList.Add(this.StepToken);
            }
            if (this._stepTokenList.Contains(next.StepToken)) throw new Exception($"步骤链中已存在相同Token的步骤，无法设置{next.StepName} 为下一步");
            this._stepTokenList.Add(next.StepToken);
            _next = next;
            _next._stepIndex = this._stepIndex + 1;
            _next._top = this;
            _next._stepTokenList = this._stepTokenList;
            return next;
        }
        /// <summary>
        /// 获取调用链中步骤总数
        /// </summary>
        /// <returns></returns>
        public int GetStepTotalCount()
        {
            return _stepTokenList?.Count ?? 1;
        }
        /// <summary>
        /// 开启任务步骤执行
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task StartAsync(CancellationToken token)
        {
            int totalCount = GetStepTotalCount();
            Console.WriteLine($"开始执行步骤 {_stepIndex}/{totalCount}：{StepName}");
            try
            {
                using (token.Register(() =>
                {
                    Console.WriteLine("任务被取消，执行清理操作...");
                }))
                {
                    await ExcuteAsync(token).ConfigureAwait(false);
                    if (_next != null)
                    {
                        await _next.StartAsync(token).ConfigureAwait(false);
                    }
                }

            }
            catch (Exception ex)
            {
                throw new Exception($"步骤 {_stepIndex}：{StepName} 执行失败，原因：{ex.Message}", ex);
            }
            finally
            {
                Console.WriteLine($"步骤{StepName} 运行结束");
            }
        }
        /// <summary>
        /// 实现具体任务步骤逻辑
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        protected abstract Task ExcuteAsync(CancellationToken token);
    }
}
